// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only

#include "surfacegraphmodifier.h"
#include <QtDataVisualization/qvalue3daxis.h>
#include <QtDataVisualization/q3dtheme.h>
#include <QtGui/qimage.h>
#include <QtCore/qmath.h>

using namespace Qt::StringLiterals;
SurfaceGraphModifier::SurfaceGraphModifier(Q3DSurface *surface)
    : m_graph(surface)
{
    m_graph->scene()->activeCamera()->setZoomLevel(85.f);
    m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetIsometricRight);
    m_graph->activeTheme()->setType(Q3DTheme::ThemeRetro);

    m_graph->setAxisX(new QValue3DAxis);
    m_graph->setAxisY(new QValue3DAxis);
    m_graph->setAxisZ(new QValue3DAxis);

    //
    // Sqrt Sin
    //
    //! [0]
    m_sqrtSinProxy = new QSurfaceDataProxy();
    m_sqrtSinSeries = new QSurface3DSeries(m_sqrtSinProxy);
    m_sqrtSinSeries->setDrawMode(QSurface3DSeries::DrawSurface);
    m_sqrtSinSeries->setFlatShadingEnabled(false);
    QLinearGradient gr;
    gr.setColorAt(0.f, Qt::darkGreen);
    gr.setColorAt(0.5f, Qt::yellow);
    gr.setColorAt(0.8f, Qt::red);
    gr.setColorAt(1.f, Qt::darkRed);

    m_sqrtSinSeries->setBaseGradient(gr);
    m_sqrtSinSeries->setColorStyle(Q3DTheme::ColorStyleRangeGradient);
    m_graph->axisX()->setLabelFormat("%d");
    m_graph->axisZ()->setLabelFormat("%d");
    m_graph->axisZ()->setTitle("PSD (ms^2/Hz)");
    m_graph->axisX()->setTitle("Hz/10000");
    m_graph->axisZ()->setTitle("秒");
    m_graph->axisX()->setTitleVisible(true);
    m_graph->axisY()->setTitleVisible(true);
    m_graph->axisZ()->setTitleVisible(true);

    // m_graph->axisX()->setRange(0, 80);//频率
    // m_graph->axisY()->setRange(0.0f, 100.0f);
    // m_graph->axisZ()->setRange(0, 180);
    m_graph->axisX()->setLabelAutoRotation(0.f);

    m_graph->axisY()->setLabelAutoRotation(90.f);
    m_graph->axisZ()->setLabelAutoRotation(0.f);
    m_graph->addSeries(m_sqrtSinSeries);
    //! [0]
    // fillSqrtSinProxy2();


    // Custom items and label
    // connect(m_graph, &QAbstract3DGraph::selectedElementChanged,
    //         this, &SurfaceGraphModifier::handleElementSelected);

    m_selectionAnimation = new QPropertyAnimation(this);
    m_selectionAnimation->setPropertyName("scaling");
    m_selectionAnimation->setDuration(500);
    m_selectionAnimation->setLoopCount(-1);

    QFont titleFont = QFont("Century Gothic", 30);
    titleFont.setBold(true);
    m_titleLabel = new QCustom3DLabel("3D时频图", titleFont,
                                      QVector3D(0.f, 1.2f, 0.f),
                                      QVector3D(1.f, 1.f, 0.f),
                                      QQuaternion());
    m_titleLabel->setPositionAbsolute(true);
    m_titleLabel->setFacingCamera(true);

    m_titleLabel->setBackgroundColor(QColor(0x66cdaa));
    m_graph->addCustomItem(m_titleLabel);
    m_graph->setShadowQuality(QAbstract3DGraph::ShadowQualityNone);
    m_titleLabel->setVisible(true);


}

SurfaceGraphModifier::~SurfaceGraphModifier()
{
    delete m_graph;
}
void SurfaceGraphModifier::setTitleName(QString s)
{
    m_titleLabel->setText(s);
}
void SurfaceGraphModifier::fillSqrtSinProxy()
{
    // 创建数据容器
    QSurfaceDataArray *dataArray = new QSurfaceDataArray;
    for (int z = 0; z < 50; z++) {
        QSurfaceDataRow *row = new QSurfaceDataRow;
        for (int x = 0; x < 150; x++) {
            // qDebug()<<x*250.0f/2048.0f;
            *row << QSurfaceDataItem(QVector3D(x, x*250.0f/2048.0f, z));
        }
        dataArray->append(row);
    }

    m_sqrtSinProxy->resetArray(dataArray);
}

void SurfaceGraphModifier::fill3DDataProxy(QVector<double>t,QVector<double>f,QVector<QVector<double>>psd)
{
    // 创建数据容器
    QSurfaceDataArray *dataArray = new QSurfaceDataArray;
    int t_len=t.size();//时间轴
    int f_len=f.size();//频率轴
    int r=t.last()/f.last();
    for (int z = 0; z < t_len; z++) {
        QSurfaceDataRow *row = new QSurfaceDataRow;
        for (int x = 0; x < f_len; x++) {
            *row << QSurfaceDataItem(QVector3D((f.at(x))*r, psd.at(z).at(x), t.at(z)));
        }
        dataArray->append(row);
    }
    m_graph->axisX()->setTitle("Hz/"+QString::number(r));
    m_sqrtSinProxy->resetArray(dataArray);
}
void SurfaceGraphModifier::fill3DDataProxy_wavelet(QVector<double>t,QVector<double>f,QVector<QVector<double>>psd)
{
    // 创建数据容器
    QSurfaceDataArray *dataArray = new QSurfaceDataArray;
    int t_len=t.size();//时间轴
    int f_len=f.size();//频率轴
    int r=t.last()/f.at(0);
    for (int z = 0; z < t_len; z++) {
        QSurfaceDataRow *row = new QSurfaceDataRow;
        for (int x = 0; x < f_len; x++) {
            *row << QSurfaceDataItem(QVector3D((f.at(0)-f.at(x))*r, psd.at(z).at(x), t.at(z)));
        }
        dataArray->append(row);
    }
    m_graph->axisX()->setTitle("Hz/"+QString::number(r));
    m_sqrtSinProxy->resetArray(dataArray);
}
void SurfaceGraphModifier::initData(int rows)
{
    // 创建数据容器
    QSurfaceDataArray *dataArray = new QSurfaceDataArray;
    for (int z = 0; z < rows; z++) {
        QSurfaceDataRow *row = new QSurfaceDataRow;
        for (int x = 0; x < 100; x++) {
            *row << QSurfaceDataItem(QVector3D(x, 0, z));
        }
        dataArray->append(row);
    }

    m_sqrtSinProxy->resetArray(dataArray);
}
void SurfaceGraphModifier::setData(int targetRow ,QSurfaceDataRow *newRow)
{
    m_sqrtSinProxy->setRow(targetRow, newRow);
    emit m_sqrtSinProxy->rowsChanged(targetRow, 1);  // 触发更新
}


void SurfaceGraphModifier::adjustXMin(int min)
{
    float minX = m_stepX * float(min) + m_rangeMinX;

    int max = m_axisMaxSliderX->value();
    if (min >= max) {
        max = min + 1;
        m_axisMaxSliderX->setValue(max);
    }
    float maxX = m_stepX * max + m_rangeMinX;

    setAxisXRange(minX, maxX);
}

void SurfaceGraphModifier::adjustXMax(int max)
{
    float maxX = m_stepX * float(max) + m_rangeMinX;

    int min = m_axisMinSliderX->value();
    if (max <= min) {
        min = max - 1;
        m_axisMinSliderX->setValue(min);
    }
    float minX = m_stepX * min + m_rangeMinX;

    setAxisXRange(minX, maxX);
}

void SurfaceGraphModifier::adjustZMin(int min)
{
    float minZ = m_stepZ * float(min) + m_rangeMinZ;

    int max = m_axisMaxSliderZ->value();
    if (min >= max) {
        max = min + 1;
        m_axisMaxSliderZ->setValue(max);
    }
    float maxZ = m_stepZ * max + m_rangeMinZ;

    setAxisZRange(minZ, maxZ);
}

void SurfaceGraphModifier::adjustZMax(int max)
{
    float maxX = m_stepZ * float(max) + m_rangeMinZ;

    int min = m_axisMinSliderZ->value();
    if (max <= min) {
        min = max - 1;
        m_axisMinSliderZ->setValue(min);
    }
    float minX = m_stepZ * min + m_rangeMinZ;

    setAxisZRange(minX, maxX);
}

//! [7]
void SurfaceGraphModifier::setAxisXRange(float min, float max)
{
    m_graph->axisX()->setRange(min, max);
}
//! [7]

void SurfaceGraphModifier::setAxisZRange(float min, float max)
{
    m_graph->axisZ()->setRange(min, max);
}
void SurfaceGraphModifier::setAxisYRange(float min, float max)
{
    m_graph->axisY()->setRange(min, max);
}
void SurfaceGraphModifier::setBlackToYellowGradient()
{
    //! [8]
    QLinearGradient gr;
    gr.setColorAt(0.f, Qt::black);
    gr.setColorAt(0.33f, Qt::blue);
    gr.setColorAt(0.67f, Qt::red);
    gr.setColorAt(1.f, Qt::yellow);

    m_sqrtSinSeries->setBaseGradient(gr);
    m_sqrtSinSeries->setColorStyle(Q3DTheme::ColorStyleRangeGradient);
    //! [8]
}

void SurfaceGraphModifier::setGreenToRedGradient()
{
    QLinearGradient gr;
    gr.setColorAt(0.f, Qt::darkGreen);
    gr.setColorAt(0.5f, Qt::yellow);
    gr.setColorAt(0.8f, Qt::red);
    gr.setColorAt(1.f, Qt::darkRed);

    m_sqrtSinSeries->setBaseGradient(gr);
    m_sqrtSinSeries->setColorStyle(Q3DTheme::ColorStyleRangeGradient);
}


void SurfaceGraphModifier::toggleSeeThrough(bool seethrough)
{
    if (seethrough) {
        m_graph->seriesList().at(0)->setDrawMode(QSurface3DSeries::DrawSurfaceAndWireframe);
    } else {
        m_graph->seriesList().at(0)->setDrawMode(QSurface3DSeries::DrawSurface);
    }
}



void SurfaceGraphModifier::toggleShadows(bool shadows)
{
    if (shadows)
        m_graph->setShadowQuality(QAbstract3DGraph::ShadowQualityMedium);
    else
        m_graph->setShadowQuality(QAbstract3DGraph::ShadowQualityNone);
}



void SurfaceGraphModifier::handleElementSelected(QAbstract3DGraph::ElementType type)
{
    resetSelection();
    if (type == QAbstract3DGraph::ElementCustomItem) {
        QCustom3DItem *item = m_graph->selectedCustomItem();
        QString text;
        if (qobject_cast<QCustom3DLabel *>(item) != 0) {
            text.append("Custom label: ");
        } else {
            QStringList split = item->meshFile().split("/");
            text.append(split.last());
            text.append(": ");
        }
        int index = m_graph->selectedCustomItemIndex();
        text.append(QString::number(index));
        m_textField->setText(text);
        m_previouslyAnimatedItem = item;
        m_previousScaling = item->scaling();
        m_selectionAnimation->setTargetObject(item);
        m_selectionAnimation->setStartValue(item->scaling());
        m_selectionAnimation->setEndValue(item->scaling() * 1.5f);
        m_selectionAnimation->start();
    } else if (type == QAbstract3DGraph::ElementSeries) {
        QString text = "Surface (";
        QSurface3DSeries *series = m_graph->selectedSeries();
        if (series) {
            QPoint point = series->selectedPoint();
            QString posStr;
            posStr.setNum(point.x());
            text.append(posStr);
            text.append(", ");
            posStr.setNum(point.y());
            text.append(posStr);
        }
        text.append(")");
        m_textField->setText(text);
    } else if (type > QAbstract3DGraph::ElementSeries
               && type < QAbstract3DGraph::ElementCustomItem) {
        int index = m_graph->selectedLabelIndex();
        QString text;
        if (type == QAbstract3DGraph::ElementAxisXLabel)
            text.append("Axis X label: ");
        else if (type == QAbstract3DGraph::ElementAxisYLabel)
            text.append("Axis Y label: ");
        else
            text.append("Axis Z label: ");
        text.append(QString::number(index));
        m_textField->setText(text);
    } else {
        m_textField->setText("Nothing");
    }
}

void SurfaceGraphModifier::resetSelection()
{
    m_selectionAnimation->stop();
    if (m_previouslyAnimatedItem)
        m_previouslyAnimatedItem->setScaling(m_previousScaling);
    m_previouslyAnimatedItem = nullptr;
}
